﻿using System;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using nRoute.Components;
using nRoute.Components.Composition;
using nRoute.Components.Routing;
using nRoute.Utilities;

namespace nRoute.Controllers.Mapping
{
    public class ControllerHandler 
        : IRouteHandler
    {
        private readonly ITypeBuilder _typeBuilder;
        private readonly Type _controllerType;

        public ControllerHandler(ITypeBuilder typeBuilder, Type controllerType)
        {
            Guard.ArgumentNotNull(controllerType, "controllerType");
            Guard.ArgumentValue(!typeof(IController).IsAssignableFrom(controllerType), "controllerType");

            _typeBuilder = typeBuilder;
            _controllerType = controllerType;
        }

#region Main Methods

        public IObservable<IUrlResponse> GetResponse(IRoutingContext context)
        {
            Guard.ArgumentNotNull(context, "context");
            Guard.ArgumentIsType(context.Request, typeof(ControllerActionRequest), "context.Request");

            // return a lazy evaluated response
            return Observable.Create<IUrlResponse>((s) =>
            {
                var _request = (ControllerActionRequest)context.Request;
                var _controller = (IController)_typeBuilder.BuildType(_controllerType);
                var _response = new ControllerContext(_request, ResponseStatus.Success, _controller, context.ParsedParameters);

                s.OnNext(_response);
                s.OnCompleted();
                return Disposable.Empty;
            });
        }

#endregion

#region IRouteHandler Members

        IObservable<IUrlResponse> IRouteHandler.GetResponse(IRoutingContext context)
        {
            return GetResponse(context);
        }

#endregion

    }
}
